<?php
/*
 * @Author: your name
 * @Date: 2020-10-14 16:56:39
 * @LastEditTime: 2020-12-28 10:08:39
 * @LastEditors: Please set LastEditors
 * @Description: 防火墙规则
 * @FilePath: /special/application/adminapiv3/service/module_manage/netfilter/FirewallRuleService.php
 */
namespace app\adminapiv3\service\module_manage\netfilter;

use app\adminapiv3\model\learn_data\HostLearnDataModel;
use app\common\exception\CustomException;
use app\common\definition\netfilter\FirewallRuleDefinition;
use app\common\definition\netfilter\LearnDataDefinition;
use app\common\service\HostLink;
use app\common\service\module_manage\netfilter\HostRule;
use think\Db;
use think\Exception;


class FirewallRuleService extends NetfilterService
{
    /**
     * @name: 防火墙规则列表
     * @Param:
     * @Description:
     * @Author: foo
     * @Date: 2019-11-05 10:34:08
     */
    public function firewallRuleList ($filterData)
    {
        $HostRule = new HostRule();
        $return = $HostRule->list($filterData);

        $fid_a = array_column($return['data'], 'fid');
        $childData = $HostRule->childList($filterData['host_id'], $fid_a);
        $return['data'] = $this->processOut($childData);

        return $return;
    }

    /**
     * @name: 添加规则
     * @Param:
     * @Description:
     * @Author: foo
     * @Date: 2019-11-05 14:37:51
     */
    public function firewallRuleAdd ($data)
    {
        $HostLink = new HostLink();
        //检查netfilter模块是否在线
        $HostLink->checkOnline('netfilter');
        //查看平台是否具有控制主机防火墙权限
        $this->CheckControlledFirewall();

        $HostRule = new HostRule();
        //处理输入的规则数组
        $insertData = $this->processInput($data, $HostRule);

        Db::startTrans();
        try {
            //添加主机规则表
            $fid_a = $this->add($insertData, $data['alias'], $HostRule, $data['scope']);
            //添加防火墙规则表
            $new_info = $this->addRealFirewallRule($data, $fid_a);
            
            //添加操作日志
            global $logArray;
            $host_name_s = $this->getHost('name', 'string');
            $logArray = array(
                'content' => '添加防火墙规则',
                'new_info' => '主机:' . $host_name_s . '规则内容:' . implode(',', array_column( $new_info, 'content'))
            );
            
            Db::commit();
        } catch (Exception $e)
        {
            Db::rollback();
            throw new CustomException('添加规则失败:' . $e->getMessage(), 422);
        }
        $return['rule_id'] = implode(',', $fid_a);

        return $return;
    }

    /**
     * @name: 防火墙规则修改
     * @Param:
     * @Description:
     * @Author: foo
     * @Date: 2019-11-05 17:24:49
     */
    public function firewallRuleModify ($updateData)
    {
        $HostRule = new HostRule();

        $list = $HostRule->childList($updateData['host_id'], $updateData['fid']);

        $data = $this->processOut($list);

        if (empty($data))
        {
            throw new CustomException('规则不存在或已被删除', 422);
        }

        $addData = $this->processInput($updateData, $HostRule);
        //查询子库中的学习数据
        $learnDataModel = new HostLearnDataModel();
        $databaseKey = $learnDataModel->setHostId($updateData['host_id']);
        $fid_a = [];
        //分布式事务
        try {
            Db::transactionXa(function () use($learnDataModel,$updateData,$addData,$HostRule, &$fid_a) {
                
                //查询旧规则数据添加操作日志
                $old_info = Db::name('netfilter_firewall_rule')->where('host_id', $updateData['host_id'])->where('source', FirewallRuleDefinition::HANDLE_RULE_SOURCE)->where('rule_id', $updateData['fid'])->column('content');
                //删除主机规则
                Db::name('host_rule')->where('host_id', $updateData['host_id'])->whereIn('fid', $updateData['fid'])->delete();

                //删除对应防火墙规则
                Db::name('netfilter_firewall_rule')->where('host_id', $updateData['host_id'])->whereIn('rule_id', $updateData['fid'])
                    ->where('source', FirewallRuleDefinition::HANDLE_RULE_SOURCE)->delete();

                //添加主机规则
                $fid_a = $this->add($addData, $updateData['alias'], $HostRule, $updateData['scope']);

                //添加用户操作日志
                $new_info = $this->addRealFirewallRule($updateData, $fid_a);
                global $logArray;
                $host_name_s = $this->getHost('name', 'string');
                $logArray = array(
                    'content' => '修改防火墙规则',
                    'old_info' => '主机:' . $host_name_s . '规则内容:' . implode(',', $old_info),
                    'new_info' => '主机:' . $host_name_s . '规则内容:' . implode(',', array_column($new_info, 'content'))
                );

                //重置学习数据 规则生成状态
                $learnDataModel->whereIn('id', $updateData['learn_id'])->update([
                    'status' => LearnDataDefinition::NOT_CREATED_RULE
                ]);

            }, [Db::connect('mysql'),Db::connect($databaseKey)]);

        } catch (Exception $e) {
            throw new CustomException('修改规则失败:' . $e->getMessage(), 422);
        }

        $return['rule_id'] = implode(',', $fid_a);
        return $return;
    }

    /**
     * @name: 规则删除
     * @Param:
     * @Description:
     * @Author: foo
     * @Date: 2019-11-05 17:32:13
     */
    public function firewallRuleDelete ($host_id, $rule_id)
    {
        $HostRule = new HostRule();
        $list = $HostRule->childList($host_id, $rule_id);
        $return = $this->processOut($list);
        if (empty($return))
        {
            throw new CustomException('该规则不存在或已被删除', 422);
        }
        $learnId_a = array_column($list, 'learn_id');

        //查询子库中的学习数据
        $learnDataModel = new HostLearnDataModel();
        $databaseKey = $learnDataModel->setHostId($host_id);

        //添加操作日志
        $old_info = Db::name('netfilter_firewall_rule')->where('host_id', $host_id)->where('source', FirewallRuleDefinition::HANDLE_RULE_SOURCE)->whereIn('rule_id', $rule_id)->column('content');
        global $logArray;
        $host_name_s = $this->getHost('name', 'string');
        $logArray = array(
            'content' => '删除防火墙规则',
            'old_info' => '主机:' . $host_name_s . '删除规则:' . implode(',', $old_info),
        );
        
        //分布式事务
        try {
            Db::transactionXa(function () use($learnDataModel,$learnId_a,$host_id,$rule_id) {
                //重置学习数据 规则生成状态
                $learnDataModel->whereIn('id', $learnId_a)->update([
                    'status' => LearnDataDefinition::NOT_CREATED_RULE
                ]);

                //删除主机规则表的规则
                Db::name('host_rule')->where('host_id', $host_id)->whereIn('fid', $rule_id)->delete();

                //删除防火墙数据表
                Db::name('netfilter_firewall_rule')->where('host_id', $host_id)->whereIn('rule_id', $rule_id)->where('source', FirewallRuleDefinition::HANDLE_RULE_SOURCE)->delete();

            }, [Db::connect('mysql'),Db::connect($databaseKey)]);

        } catch (Exception $e) {
            throw new CustomException('删除规则失败:' .$e->getMessage(), 403);
        }

        return $return;
    }

    /**
     * @name: 启用规则
     * @Param:
     * @Description:
     * @Author: foo
     * @Date: 2019-11-12 13:52:58
     */
    public function firewallRuleOn ($host_id, $rule_id)
    {
        $HostRule = new HostRule();
        $list = $HostRule->childList($host_id, $rule_id);
        if(empty($list))
        {
            throw new CustomException('规则未找到请确认后启用', 422);
        }
        $return = $this->processOut($list);
        $return = array_filter($return, function($v){
            if($v['status'] == FirewallRuleDefinition::RULE_DISABLE)
            {
                return $v;
            }
        });

        if(!$return){
            throw new CustomException('所选规则已经启用',$this->CODE_FAIL);
        }

        $learnId_a = array_column($list, 'learn_id');

        //查询子库中的学习数据
        $learnDataModel = new HostLearnDataModel();
        $databaseKey = $learnDataModel->setHostId($host_id);

        //分布式事务
        try {
            Db::transactionXa(function () use($learnDataModel,$learnId_a,$host_id,$rule_id,$return) {
                //重置学习数据 规则生成状态
                $learnDataModel->whereIn('id', $learnId_a)->update([
                    'status' => LearnDataDefinition::CREATED_RULE
                ]);

                //修改状态 自定义规则列表下发状态为 启用
                Db::name('host_rule')->where('host_id', $host_id)->whereIn('fid', $rule_id)->update([
                    'status' => FirewallRuleDefinition::RULE_ENABLE
                ]);

                //添加规则到 下发规则表中
                $new_info = $this->addRealFirewallRule($return);

                //添加操作日志
                global $logArray;
                $host_name_s = $this->getHost('name', 'string');
                $logArray = array(
                    'content' => '启用防火墙规则',
                    'new_info' => '主机:' . $host_name_s . '规则内容:' . implode(',', array_column($new_info, 'content'))
                );

            }, [Db::connect('mysql'),Db::connect($databaseKey)]);

        } catch (Exception $e) {
            throw new CustomException('启用规则失败:' .$e->getMessage(), 403);
        }

        return $return;

    }

    /**
     * @name: 禁用规则
     * @Param:
     * @Description:
     * @Author: foo
     * @Date: 2019-11-12 13:52:58
     */
    public function firewallRuleOff ($host_id, $rule_id)
    {
        $HostRule = new HostRule();
        $list = $HostRule->childList($host_id, $rule_id);

        if(empty($list))
        {
            throw new CustomException('规则未找到请确认后禁用', 422);
        }

        $learnId_a = array_column($list, 'learn_id');

        //查询子库中的学习数据
        $learnDataModel = new HostLearnDataModel();
        $databaseKey = $learnDataModel->setHostId($host_id);

        //添加操作日志
        $old_info = Db::name('netfilter_firewall_rule')->where('host_id', $host_id)->where('source', FirewallRuleDefinition::HANDLE_RULE_SOURCE)->whereIn('rule_id', $rule_id)->column('content');
        global $logArray;
        $host_name_s = $this->getHost('name', 'string');
        $logArray = array(
            'content' => '禁用防火墙规则',
            'old_info' => '主机:' . $host_name_s . '规则内容:' . implode(',', array_column($old_info, 'content'))
        );

        //分布式事务
        try {
            Db::transactionXa(function () use($learnDataModel,$learnId_a,$host_id,$rule_id) {
                //重置学习数据 规则生成状态
                $learnDataModel->whereIn('id', $learnId_a)->update([
                    'status' => LearnDataDefinition::NOT_CREATED_RULE
                ]);

                //修改状态 自定义规则列表下发状态为 禁用
                Db::name('host_rule')->where('host_id', $host_id)->whereIn('fid', $rule_id)->update([
                    'status' => FirewallRuleDefinition::RULE_DISABLE
                ]);

                // 删除下发列表 规则
                Db::name('netfilter_firewall_rule')->where('host_id', $host_id)->whereIn('rule_id', $rule_id)->where('source', FirewallRuleDefinition::HANDLE_RULE_SOURCE)->delete();

            }, [Db::connect('mysql'),Db::connect($databaseKey)]);

        } catch (Exception $e) {
            throw new CustomException('禁用规则失败:' .$e->getMessage(), 403);
        }


    }
}